#ifndef __MAP_H_INCLUDED__
#define __MAP_H_INCLUDED__

#include <map>

#include <glf/heap/heap.h>

//TODO support copy of fmap
//untested

namespace glf {

template <class T>
struct FMapAlloc
{
	typedef T        value_type;
	typedef T*       pointer;
	typedef const T* const_pointer;
	typedef T&       reference;
	typedef const T& const_reference;
	typedef std::size_t    size_type;
	typedef std::ptrdiff_t difference_type;

	// rebind allocator to type U
	template <class U>
	struct rebind {
		typedef FMapAlloc<U> other;
	};

	pointer address (reference value) const {
		return &value;
	}
	const_pointer address (const_reference value) const {
		return &value;
	}

	Heap& m_heap;

	FMapAlloc(Heap& h) :
		m_heap(h)
	{}
/*
	FMapAlloc(const FMapAlloc& a)throw()  :
		m_heap(a.m_heap)
	{
	}*/

	template <class U>
	FMapAlloc (const FMapAlloc<U>& fma) throw() :
		m_heap(fma.m_heap)
	{ }
	~FMapAlloc() throw() {}

	size_type max_size () const throw() {
		return m_heap.GetTotalSize();
	}

	pointer allocate (size_type num, const void* = 0) {
		
		GLFi_ASSERT(num == 1);

		pointer p = (pointer)m_heap.Alloc(sizeof(T));

		GLFi_ASSERT(p);

		return p;
	}

	void construct (pointer p, const T& value) {
		new (p) T(value);
	}

	void destroy (pointer p) {
		p->~T();
	}

	void deallocate (pointer p, size_type num) {
		GLFi_ASSERT(num == 1);
		m_heap.Free(p);
	}
};

// return that all specializations of this allocator are interchangeable
template <class T1, class T2>
bool operator== (const FMapAlloc<T1>&, const FMapAlloc<T2>&) throw() {
return true;
}
template <class T1, class T2>
bool operator!= (const FMapAlloc<T1>&, const FMapAlloc<T2>&) throw() {
return false;
}

template<int SIZE, typename KTYPE, typename TYPE>
struct Allocatable
{
	char m_buffer[(sizeof(std::pair<KTYPE,TYPE>)+32) * SIZE * 2];
	
	UnitHeap m_heap;

	Allocatable() :
		m_heap(sizeof(m_buffer), m_buffer, sizeof(std::pair<KTYPE,TYPE>))
	{
		m_buffer[0] = m_buffer[1];
	}
};

template<int SIZE, typename KTYPE, typename TYPE, typename CMP=std::less<KTYPE>, typename ALLOC=FMapAlloc<std::pair<KTYPE,TYPE> > >
struct fmap : public Allocatable<SIZE,KTYPE,TYPE>, std::map<KTYPE,TYPE,CMP,ALLOC>
{
	fmap() : 
		Allocatable<SIZE,KTYPE,TYPE>(),
		std::map<KTYPE,TYPE,CMP,ALLOC>(CMP(), ALLOC(m_heap))
	{}

//private:
	fmap(const fmap& fm) :
		Allocatable<SIZE,KTYPE,TYPE>(),
		std::map<KTYPE,TYPE,CMP,ALLOC>(fm.begin(), fm.end(), CMP(), ALLOC(m_heap))
	{
	}

	fmap& operator=(const fmap& fm)
	{
		if(&fm != this)
		{
			m_heap.FreeAll();
			clear();
			
			for(std::map<KTYPE,TYPE,CMP,ALLOC>::const_iterator it = fm.begin(); it != fm.end(); ++it)
				insert(*it);
		}

		return *this;
	}
};
} //namespace glf

#endif
